﻿using System;
using System.Windows.Media;
using Microsoft.Silverlight.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SilverMindMap.Core.Model;
using SilverMindMap.Core.Tests.TestHelpers;

namespace SilverMindMap.Core.Tests.Model
{
    [TestClass]
    public class NodeTests
    {
        [TestMethod]
        [Tag(TestTags.BVT)]
        public void CaptionTest()
        {
            var node = new Node();
            Assert.AreEqual("", node.Caption, "Invalid default value of Caption");

            node.Caption = "Foo";
            Assert.AreEqual("Foo", node.Caption, "Invalid value of caption set by the setter");

            node.Caption = null;
            Assert.AreEqual("", node.Caption, "Setting Caption to null should convert it to an empty string");
        }

        [TestMethod]
        public void CaptionNotificationTest()
        {
            var node = new Node();
            node.Caption = "Value1";
            
            string changedPropertyName = null;
            string changedPropertyValue = null;
            int changedPropertyNotificationsCount = 0;

            node.PropertyChanged += (s, a) =>
                {
                    changedPropertyNotificationsCount++;
                    changedPropertyName = a.PropertyName;
                    changedPropertyValue = node.Caption;
                };

            node.Caption = "Value2";

            Assert.AreEqual(1, changedPropertyNotificationsCount);
            Assert.AreEqual("Caption", changedPropertyName);
            Assert.AreEqual("Value2", changedPropertyValue);
        }

        [TestMethod]
        [Tag(TestTags.BVT)]
        public void HyperlinkTest()
        {
            var node = new Node();
            Assert.IsNull(node.Hyperlink);

            var uri = new Uri("http://www.microsoft.com", UriKind.Absolute);
            node.Hyperlink = uri;
            Assert.AreEqual(uri, node.Hyperlink);
        }

        [TestMethod]
        public void HyperlinkNotificationTest()
        {
            var node = new Node();
            var uri = new Uri("http://www.microsoft.com", UriKind.Absolute);

            string changedPropertyName = null;
            Uri changedPropertyValue = null;
            int changedPropertyNotificationCount = 0;

            node.PropertyChanged += (s, a) =>
                {
                    changedPropertyNotificationCount++;
                    changedPropertyName = a.PropertyName;
                    changedPropertyValue = node.Hyperlink;
                };

            node.Hyperlink = uri;

            Assert.AreEqual(1, changedPropertyNotificationCount);
            Assert.AreEqual("Hyperlink", changedPropertyName);
            Assert.AreEqual(uri, changedPropertyValue);
        }

        [TestMethod]
        [Tag(TestTags.BVT)]
        public void BackgroundColorTest()
        {
            var node = new Node();
            Assert.AreEqual(Node.DefaultBackgroundColor, node.BackgroundColor);

            var newColor = Colors.Green;
            node.BackgroundColor = newColor;
            Assert.AreEqual(newColor, node.BackgroundColor);
        }

        [TestMethod]
        public void BackgroundColorNotificationTest()
        {
            var node = new Node();
            var newColor = Colors.Green;

            string changedPropertyName = null;
            Color changedPropertyValue = Colors.Transparent;
            int changedPropertyNotificationCount = 0;

            node.PropertyChanged += (s, a) =>
                {
                    changedPropertyNotificationCount++;
                    changedPropertyName = a.PropertyName;
                    changedPropertyValue = node.BackgroundColor;
                };

            node.BackgroundColor = newColor;

            Assert.AreEqual(1, changedPropertyNotificationCount);
            Assert.AreEqual("BackgroundColor", changedPropertyName);
            Assert.AreEqual(newColor, changedPropertyValue);
        }

        [TestMethod]
        [Tag(TestTags.BVT)]
        public void ForegroundColorTest()
        {
            var node = new Node();
            Assert.AreEqual(Node.DefaultForegroundColor, node.ForegroundColor);

            var newColor = Colors.Green;
            node.ForegroundColor = newColor;
            Assert.AreEqual(newColor, node.ForegroundColor);
        }

        [TestMethod]
        public void ForegroundColorNotificationTest()
        {
            var node = new Node();
            var newColor = Colors.Green;

            string changedPropertyName = null;
            Color changedPropertyValue = Colors.Transparent;
            int changedPropertyNotificationCount = 0;

            node.PropertyChanged += (s, a) =>
            {
                changedPropertyNotificationCount++;
                changedPropertyName = a.PropertyName;
                changedPropertyValue = node.ForegroundColor;
            };

            node.ForegroundColor = newColor;

            Assert.AreEqual(1, changedPropertyNotificationCount);
            Assert.AreEqual("ForegroundColor", changedPropertyName);
            Assert.AreEqual(newColor, changedPropertyValue);
        }

        [TestMethod]
        [Tag(TestTags.BVT)]
        public void MindMapTest()
        {
            var node = new Node();
            var mindMap = new MindMap();

            Assert.IsNull(node.MindMap);
            node.MindMap = mindMap;
            Assert.AreSame(mindMap, node.MindMap);
        }

        [TestMethod]
        public void MindMapNotificationTest()
        {
            var node = new Node();

            string changedPropertyName = null;
            MindMap changedPropertyValue = null;
            int changedPropertyNotificationsCount = 0;

            node.PropertyChanged += (s, a) =>
                {
                    changedPropertyNotificationsCount++;
                    changedPropertyName = a.PropertyName;
                    changedPropertyValue = node.MindMap;
                };

            var mindMap = new MindMap();
            node.MindMap = mindMap;

            Assert.AreEqual(1, changedPropertyNotificationsCount);
            Assert.AreEqual("MindMap", changedPropertyName);
            Assert.AreSame(mindMap, changedPropertyValue);
        }

        [TestMethod]
        [Tag(TestTags.BVT)]
        public void ParametrizedConstructorTest()
        {
            var node1 = new Node("Bar");
            Assert.AreEqual("Bar", node1.Caption, "Parametrized constructor didn't correctly set Caption property for not-null argument");

            var node2 = new Node(null);
            Assert.AreEqual("", node2.Caption, "Parametrized constructor didn't correctly set Caption property for null argument");
        }

        [TestMethod]
        [Tag(TestTags.BVT)]
        public void AddLinkAndGetLinkToTest()
        {
            var node1 = new Node("1");
            var node2 = new Node("2");
            var node3 = new Node("3");
            
            var link1_2 = node1.AddLink(node2);
            var link2_3 = node2.AddLink(node3);

            Assert.AreSame(node1, link1_2.FirstNode);
            Assert.AreSame(node2, link1_2.SecondNode);
            Assert.AreSame(node2, link2_3.FirstNode);
            Assert.AreSame(node3, link2_3.SecondNode);

            Assert.AreSame(link1_2, node1.GetLink(node2));
            Assert.AreSame(link1_2, node2.GetLink(node1));
            Assert.AreSame(link2_3, node2.GetLink(node3));
            Assert.AreSame(link2_3, node3.GetLink(node2));
            Assert.IsNull(node1.GetLink(node3));
            Assert.IsNull(node3.GetLink(node1));

            Assert.AreEqual(1, node1.Links.Count);
            Assert.AreEqual(2, node2.Links.Count);
            Assert.AreEqual(1, node3.Links.Count);
        }

        [TestMethod]
        public void AddAndRemoveLinkToItselfTest()
        {
            var node = new Node("1");
            var link = node.AddLink(node);
            
            Assert.AreSame(node, link.FirstNode);
            Assert.AreSame(node, link.SecondNode);
            Assert.AreSame(link, node.GetLink(node));

            Assert.IsTrue(node.RemoveLink(link));
            Assert.IsNull(node.GetLink(node));

            Assert.IsFalse(node.RemoveLink(link));
        }

        [TestMethod]
        public void AddDuplicateLinkedNodeTest()
        {
            var node1 = new Node("1");
            var node2 = new Node("2");

            node1.AddLink(node2);
            ExceptionAssert.Thrown(
                () => node1.AddLink(node2),
                e => e is ArgumentException,
                "ArgumentException was expected when trying to call AddLinkedNode for already linked node (case 1)");

            ExceptionAssert.Thrown(
                () => node2.AddLink(node1),
                e => e is ArgumentException,
                "ArgumentException was expected when trying to call AddLinkedNode for already linked node (case 2)");
        }

        [TestMethod]
        [Tag(TestTags.BVT)]
        public void RemoveLinkedNodeTest()
        {
            var node1 = new Node("1");
            var node2 = new Node("2");
            var node3 = new Node("3");

            var link1_2 = node1.AddLink(node2);
            var link1_3 = node1.AddLink(node3);

            Assert.IsTrue(node2.RemoveLink(node1));
            
            Assert.AreSame(link1_3, node1.GetLink(node3));
            Assert.AreSame(link1_3, node3.GetLink(node1));
            Assert.IsNull(node1.GetLink(node2));
            Assert.IsNull(node2.GetLink(node1));

            Assert.IsFalse(node1.RemoveLink(node2));
        }
    }
}
